package com.funong.matrix.core.utils.zip;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONException;
import com.funong.matrix.biz.system.pojo.dto.FileBaseInfoDTO;
import com.funong.matrix.core.utils.DateTimeUtil;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author NaNa
 * @since 2020-06-02 17:43
 */
public class FileUploadUtil {
    private static final String PATH = "fileRecord/upload/file/";

    /**
     * 单文件上传
     *
     * @param file
     * @param request
     * @return
     * @throws IllegalStateException
     * @throws IOException
     * @throws JSONException
     */
    public static FileBaseInfoDTO singleUpload(MultipartFile file, HttpServletRequest request)
            throws IllegalStateException, IOException, JSONException {
        return singleUpload(file, request, null, null);
    }

    /**
     * 单文件上传
     *
     * @param file
     * @param request
     * @param bizModule   文件模块
     * @param bizCategory 文件类型
     * @return
     * @throws IllegalStateException
     * @throws IOException
     * @throws JSONException
     */
    public static FileBaseInfoDTO singleUpload(MultipartFile file, HttpServletRequest request, String bizModule, String bizCategory)
            throws IllegalStateException, IOException, JSONException {
        String newPath = PATH;
        if (StrUtil.isNotBlank(bizModule)) {
            newPath = newPath + bizModule.toLowerCase() + "/";
        }
        if (StrUtil.isNotBlank(bizCategory)) {
            newPath = newPath + bizCategory.toLowerCase() + "/";
        }
        newPath = newPath + DateTimeUtil.formatDateString();
        if (!file.isEmpty()) {
            //定义文件
            File parentFile = new File(newPath);
            judeDirExists(parentFile);
            //上传文件
            return uploadFile(newPath, parentFile, file);
        } else {
            return null;
        }
    }

    /**
     * 多文件上传
     *
     * @param files
     * @param request
     * @return
     * @throws IllegalStateException
     * @throws IOException
     * @throws JSONException
     */
    public static List<FileBaseInfoDTO> multiUpload(MultipartFile[] files, HttpServletRequest request)
            throws IllegalStateException, IOException, JSONException {
        if (files.length > 0) {
            //创建这个集合保存所有文件的信息
            List<FileBaseInfoDTO> listMap = new ArrayList<>();
            String newPath = PATH + DateTimeUtil.formatDateString();
            //定义文件
            File parentFile = new File(newPath);
            judeDirExists(parentFile);
            //循环多次上传多个文件
            for (MultipartFile file : files) {
                //创建map对象保存每一个文件的信息
                FileBaseInfoDTO fileBaseInfoDTO = uploadFile(newPath, parentFile, file);
                listMap.add(fileBaseInfoDTO);
            }
            //以json方式输出到页面
            return listMap;
        } else {
            return null;
        }
    }

    /**
     * 统一上传文件
     *
     * @param newPath
     * @param parentFile
     * @param file
     * @return
     * @throws IOException
     */
    private static FileBaseInfoDTO uploadFile(String newPath, File parentFile, MultipartFile file) throws IOException {
        String oldName = file.getOriginalFilename();
        oldName = getLegalName(oldName);
        Long size = file.getSize();
        //使用TmFileUtil文件上传工具获取文件的各种信息
        //优化文件大小
        String sizeString = readableFileSize(size);
        //获取文件后缀名
        String stuff = getFileStuff(oldName);
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        //文件最终上传的位置
        String newFileName = uuid + "_" + oldName;
        String url = newPath + "/" + newFileName;
        //文件传输，parent文件
        file.transferTo(new File(parentFile.getAbsolutePath() + File.separator + newFileName));
        return new FileBaseInfoDTO().setAttachName(newFileName)
                .setOriginalName(oldName)
                .setAttachUrl(url)
                .setSize(size.intValue())
                .setSizeInfo(sizeString)
                .setAttachStuff(stuff);
    }

    /**
     * 获取文件后缀名
     *
     * @param oldName
     * @return
     */
    private static String getFileStuff(String oldName) {
        return oldName.substring(oldName.lastIndexOf("."));
    }

    /**
     * 获取文件后缀名
     *
     * @param oldName
     * @return
     */
    private static String getFileNameNoEx(String oldName) {
        return oldName.substring(0, oldName.lastIndexOf("."));
    }

    /**
     * 判断文件夹，并创建
     *
     * @param file 要创建的文件
     */
    public static void judeDirExists(File file) {
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 文件字节数转换为文件大小
     *
     * @param size 文件字节数
     * @return 换算的文件大小结果（B、KB、MB）
     */
    private static String readableFileSize(long size) {
        if (size <= 0) {
            return "0";
        }
        final String[] units = new String[]{"B", "kB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,##0.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
    }

    /**
     * 写入文件
     *
     * @param target
     * @param src
     * @throws IOException
     */
    public static void write(String filePath, String target, InputStream src) throws IOException {

        //定义文件
        File parentFile = new File(filePath);
        judeDirExists(parentFile);

        OutputStream os = new FileOutputStream(target);
        byte[] buf = new byte[1024];
        int len;
        while (-1 != (len = src.read(buf))) {
            os.write(buf, 0, len);
        }
        os.flush();
        os.close();
    }

    /**
     * 获取合法文件名
     *
     * @param fileName
     * @return
     */
    public static String getLegalName(String fileName) {
        String fileNameNoEx = getFileNameNoEx(fileName);
        fileNameNoEx = fileNameNoEx.replace("(", "（");
        fileNameNoEx = fileNameNoEx.replace(")", "）");
        String suffix = getFileStuff(fileName);
        // 非法字符  modify 去掉小数点的限制 ".",
        String[] illegalChars = new String[]{
                "~", "!", "@", "#", "$", "%", "^", "&", "*",
                "(", ")", "_", "+", "`", "-", "=", "{", "}",
                "[", "]", ";", "'", "\\", ":", "\"", "|", "<",
                ">", "?", ",",  "/"};
        for (String c : illegalChars) {
            fileNameNoEx = fileNameNoEx.replace(c, "");
        }
        if (StrUtil.isBlank(fileNameNoEx)) {
            fileNameNoEx = "1";
        }
        return fileNameNoEx + suffix;
    }

}
